import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
import { DefaultStage } from "../default-stage";
import { RawAssetsUrl } from "../../raw-assets-info";
import { Helper } from "babylon-lib/tool/helper";
import { AnimationFrame } from "babylon-lib/index";
import * as Data from '../../data/data';


class InitializeAssets {

    public static characterMap: Map<string, TransformNode>;
    public static animationMap: Map<string, TransformNode>;
    public static headMap: Map<string, TransformNode>;
    public static clothesMap: Map<string, TransformNode>;
    public static coatMap: Map<string, TransformNode>;
    public static clothesModel: TransformNode;
    public static coatModel: TransformNode;

    public static initialize(stage: DefaultStage): void {
        this.setModel(stage);
        this.setHead(stage);
        this.setClothes(stage);
        this.setCoat(stage);
        this.setAnimation(stage);

        let activeOutfit: Map<string, TransformNode> = this.clothesMap;
        AnimationFrame.request(() => {
            this.animationMap.forEach(t => {
                const character = this.characterMap.get(t.name)!;
                character.position.copyFrom(t.position);
                character.rotationQuaternion?.copyFrom(t.rotationQuaternion!);

                const head = this.headMap.get(t.name);
                head?.position.copyFrom(t.position);
                head?.rotationQuaternion?.copyFrom(t.rotationQuaternion!);

                const outfit = activeOutfit.get(t.name)!;
                outfit.position.copyFrom(t.position);
                outfit.rotationQuaternion?.copyFrom(t.rotationQuaternion!);
            });
        }, 16, 200, {});

        Data.outfitIndex.onChange((o, n) => {
            activeOutfit = n === 0 ? this.clothesMap : this.coatMap;
            
            this.animationMap.forEach(t => {
                const outfit = activeOutfit.get(t.name)!;
                outfit.position.copyFrom(t.position);
                outfit.rotationQuaternion?.copyFrom(t.rotationQuaternion!);
            });

            Helper.getChildMeshes(this.coatModel).forEach(mesh => {
                mesh.isVisible = n === 1;
            });
            Helper.getChildMeshes(this.clothesModel).forEach(mesh => {
                mesh.isVisible = n === 0;
            });
        });
    }

    private static setCoat(stage: DefaultStage) {
        const model = stage.loader(stage.mainScene).getMeshTaskInfo(RawAssetsUrl.characterCoatModel)!;
        const rootNode = Helper.rootTransformNode(model.loadedTransformNodes!)[0]!;
        rootNode.scaling.scaleInPlace(0.01);

        const coatMap = new Map<string, TransformNode>();
        model.loadedSkeletons![0].bones.forEach(bone => {
            coatMap.set(bone.name, bone.getTransformNode()!);
        })

        Helper.getChildMeshes(rootNode).forEach(mesh => {
            mesh.isVisible = false;
        });

        this.coatMap = coatMap;
        this.coatModel = rootNode;
    }

    private static setClothes(stage: DefaultStage) {
        const model = stage.loader(stage.mainScene).getMeshTaskInfo(RawAssetsUrl.characterClothesModel)!;
        const rootNode = Helper.rootTransformNode(model.loadedTransformNodes!)[0]!;
        rootNode.scaling.scaleInPlace(0.01);

        const clothesMap = new Map<string, TransformNode>();
        model.loadedSkeletons![0].bones.forEach(bone => {
            clothesMap.set(bone.name, bone.getTransformNode()!);
        });
        this.clothesMap = clothesMap;
        this.clothesModel = rootNode;
    }

    private static setHead(stage: DefaultStage) {
        const model = stage.loader(stage.mainScene).getMeshTaskInfo(RawAssetsUrl.characterHeadModel)!;
        const rootNode = Helper.rootTransformNode(model.loadedTransformNodes!)[0]!;
        rootNode.scaling.scaleInPlace(0.01);

        const skeleton = model.loadedSkeletons![0];
        const headMap = new Map<string, TransformNode>();
        skeleton.bones.forEach(bone => {
            headMap.set(bone.name, bone.getTransformNode()!);
        })
        this.headMap = headMap;
    }

    private static setModel(stage: DefaultStage) {
        const model = stage.loader(stage.mainScene).getMeshTaskInfo(RawAssetsUrl.characterFemalModel)!;
        let rootNode = Helper.rootTransformNode(model.loadedTransformNodes!)[0]!;
        rootNode.scaling.scaleInPlace(0.01);
        // console.log(model)

        const modelMap = new Map<string, TransformNode>();
        model.loadedSkeletons![0].bones.forEach(bone => {
            modelMap.set(bone.name, bone.getTransformNode()!);
        })
        this.characterMap = modelMap;
    }

    private static setAnimation(stage: DefaultStage) {
        let animationModel = stage.loader(stage.mainScene).getMeshTaskInfo(RawAssetsUrl.characterFemalAnimation)!;
        const animationMap = new Map<string, TransformNode>();
        animationModel.loadedAnimationGroups![0].targetedAnimations.forEach(t => {
            animationMap.set(t.target.name, t.target);
        });

        animationModel.loadedAnimationGroups!.forEach(ani => {
            ani.stop();
            ani.play(true);
        });
        this.animationMap = animationMap;
    }

}


export { InitializeAssets };